package util

import (
    "encoding/binary"
    "errors"
    "fmt"

    "github.com/cloudwego/hertz/pkg/common/hlog"
)

// 气象传感器 - 铝壳风速传感器（485型，ZTS-3000-FSA-N01）

// WindSensorData 解析后的风速传感器数据
type WindSensorData struct {
    DeviceAddr  byte    // 设备地址（1-254，默认0x01）
    FuncCode    byte    // 功能码（读：0x03；写：0x06）
    ValidBytes  byte    // 应答帧有效数据字节数
    InstantWind float64 // 瞬时风速（单位：m/s，分辨率0.1m/s）
    //转换后的风速等级名称
    WindLevelName string // 瞬时风速等级名称
    //转换后的风速等级
    WindLevel     int    // 瞬时风速等级
    BaudRate      uint16 // 设备波特率（对应值：0=2400,1=4800<默认>,2=9600...7=1200）
    NewDeviceAddr uint16 // 新设备地址（仅修改地址时使用，1-254）
}

// BuildWindRequestFrame 构建风速传感器请求帧（支持读风速、改地址、改波特率）
// deviceAddr: 设备地址（默认0x01）
// funcCode: 功能码（读风速：0x03；写参数：0x06）
// startAddr: 起始寄存器地址（风速：0x0000；地址配置：0x07D0；波特率配置：0x07D1）
// dataLength: 读取寄存器数量/写入参数值（读风速：0x0001；写参数：新地址/波特率对应值）
func BuildWindRequestFrame(deviceAddr, funcCode byte, startAddr, dataLength uint16) ([]byte, error) {
    // 校验参数合法性（基于传感器手册定义）
    if deviceAddr < 0x01 || deviceAddr > 0xFE {
        return nil, errors.New("设备地址非法，需在1-254范围内")
    }
    if funcCode != 0x03 && funcCode != 0x06 {
        return nil, errors.New("仅支持功能码0x03（读）和0x06（写）")
    }
    // 校验寄存器地址（仅支持手册中定义的关键寄存器）
    validStartAddrs := map[uint16]bool{0x0000: true, 0x07D0: true, 0x07D1: true}
    if !validStartAddrs[startAddr] {
        return nil, fmt.Errorf("起始寄存器地址非法，仅支持0x0000(风速)、0x07D0(地址)、0x07D1(波特率)")
    }
    // 打印请求帧日志
    hlog.Debugf("构建风速传感器请求帧: 设备地址=0x%02X, 功能码=0x%02X, 起始寄存器=0x%04X, 数据长度/值=0x%04X",
        deviceAddr, funcCode, startAddr, dataLength)

    // 构建帧主体（6字节：地址码+功能码+起始地址(2字节)+数据长度/值(2字节)）
    frame := make([]byte, 6)
    frame[0] = deviceAddr
    frame[1] = funcCode
    binary.BigEndian.PutUint16(frame[2:4], startAddr)  // 寄存器地址高位在前
    binary.BigEndian.PutUint16(frame[4:6], dataLength) // 读：寄存器数量；写：参数值

    // 计算并添加CRC16校验码（低位在前，高位在后）
    crc := calculateWindCRC(frame)
    frame = append(frame, byte(crc&0xFF))    // CRC低字节
    frame = append(frame, byte(crc>>8&0xFF)) // CRC高字节

    return frame, nil
}

// ParseWindResponseFrame 解析风速传感器应答帧（支持读风速、写参数确认）
// response: 传感器返回的原始应答字节流
func ParseWindResponseFrame(response []byte) (*WindSensorData, error) {
    // 1. 基础长度校验（最小长度：读应答7字节，写应答8字节）
    if len(response) < 7 {
        return nil, errors.New("应答帧长度不足，最小需7字节")
    }
    // 2. 提取帧头信息
    deviceAddr := response[0]
    funcCode := response[1]
    // 3. 错误功能码检查（功能码最高位为1表示设备返回错误）
    if (funcCode & 0x80) != 0 {
        return nil, fmt.Errorf("设备返回错误，错误功能码=0x%02X", funcCode)
    }
    //校验码低位 0x38 校验码高位 0x7A
    if response[len(response)-2] != 0x38 || response[len(response)-1] != 0x7A {
        return nil, errors.New("校验码错误")
    }

    // 4. CRC校验（校验范围：除最后2字节CRC外的所有数据）
    dataPart := response[:len(response)-2]
    receivedCRC := binary.LittleEndian.Uint16(response[len(response)-2:]) // 接收的CRC（低位在前）
    calculatedCRC := calculateWindCRC(dataPart)
    if receivedCRC != calculatedCRC {
        return nil, fmt.Errorf("CRC校验失败，接收CRC=0x%04X，计算CRC=0x%04X", receivedCRC, calculatedCRC)
    }

    // 5. 按功能码分场景解析数据
    result := &WindSensorData{
        DeviceAddr: deviceAddr,
        FuncCode:   funcCode,
    }

    // 场景1：功能码0x03（读取风速数据，应答帧7字节：地址+功能码+有效字节数+风速(2字节)+CRC(2字节)）
    // 有效字节数校验（读1个寄存器需返回2字节数据，故有效字节数=0x02）
    validBytes := response[2]
    if validBytes != 0x02 {
        return nil, fmt.Errorf("读风速应答有效字节数异常，期望0x02，实际0x%02X", validBytes)
    }
    result.ValidBytes = validBytes

    // 解析瞬时风速（寄存器0x0000数据为真实值的10倍，需除以10）
    windRaw := binary.BigEndian.Uint16(response[3:5])
    result.InstantWind = float64(windRaw) / 10.0
    hlog.Debugf("解析风速数据：设备地址=0x%02X，瞬时风速=%.1f m/s", deviceAddr, result.InstantWind)
    // 6. 转换风速等级
    result.WindLevel, result.WindLevelName, _ = result.GetWindLevel()
    return result, nil
}

// calculateWindCRC 计算ModBus-RTU CRC16校验码（多项式0xA001，低位在前）
// 符合传感器手册中“错误校验采用CRC冗余循环码”的定义
func calculateWindCRC(data []byte) uint16 {
    crc := uint16(0xFFFF) // 初始值
    for _, b := range data {
        crc ^= uint16(b)
        for i := 0; i < 8; i++ {
            if (crc & 0x0001) != 0 { // 检查最低位
                crc >>= 1
                crc ^= 0xA001 // 多项式
            } else {
                crc >>= 1
            }
        }
    }
    return crc
}

// GetWindLevel 根据瞬时风速获取风力等级（参考传感器手册“风力等级表”）
func (w *WindSensorData) GetWindLevel() (int, string, error) {
    if w.InstantWind < 0 {
        return -1, "", errors.New("风速值非法，不能为负数")
    }

    // 风力等级划分（对应手册中“17级风力等级表”核心区间）
    switch {
    case w.InstantWind <= 0.2:
        return 0, "无风", nil
    case w.InstantWind <= 1.5:
        return 1, "软风", nil
    case w.InstantWind <= 3.3:
        return 2, "软风", nil
    case w.InstantWind <= 5.4:
        return 3, "微风", nil
    case w.InstantWind <= 7.9:
        return 4, "和风", nil
    case w.InstantWind <= 10.7:
        return 5, "清劲风", nil
    case w.InstantWind <= 13.8:
        return 6, "强风", nil
    case w.InstantWind <= 17.1:
        return 7, "疾风", nil
    case w.InstantWind <= 20.7:
        return 8, "大风", nil
    case w.InstantWind <= 24.4:
        return 9, "烈风", nil
    case w.InstantWind <= 28.4:
        return 10, "狂风", nil
    case w.InstantWind <= 32.6:
        return 11, "暴风", nil
    case w.InstantWind <= 36.9:
        return 12, "飓风", nil
    case w.InstantWind <= 41.4:
        return 13, "飓风", nil
    case w.InstantWind <= 46.1:
        return 14, "飓风", nil
    case w.InstantWind <= 50.9:
        return 15, "飓风", nil
    case w.InstantWind <= 56.0:
        return 16, "飓风", nil
    case w.InstantWind <= 61.2:
        return 17, "飓风", nil
    default:
        return -1, "超量程", nil
    }
}
